package interpreter.operation;

import interpreter.Registers;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Roderland
 * @since 1.0
 */
public class Instruct {
    static Pattern pattern = Pattern.compile(
            "(\\w+)(\\s)*+((%\\w+|\\$0x[0-9A-Fa-f]+)|(\\((%\\w+|\\$0x[0-9A-Fa-f]+)\\)))*(,((%\\w+)|(\\(%\\w+\\))))*"
    );
    Opcode op;
    Operand src;
    Operand dest;
    String sourceCode;

    public Instruct(String s) {
        sourceCode = s;
        Matcher matcher = pattern.matcher(s);
        if (matcher.find()) {
            String opcode = matcher.group(1);
            String arg1 = matcher.group(3);
            String arg2 = matcher.group(8);
            switch (opcode) {
                case "mov": {
                    // ($0x1f) $0x1f %eax (%eax)
                    // arg1
                    if (arg1.startsWith("$0x")) {
                        src = new Operand(OpType.IMM, Integer.parseInt(arg1.substring(3)));
                    } else if (arg1.startsWith("($0x")) {
                        src = new Operand(OpType.MM_IMM, Integer.parseInt(arg1.substring(4, arg1.length() - 1)));
                    } else if (arg1.startsWith("%")) {
                        String reg = arg1.substring(1);
                        src = new Operand(OpType.REG, Registers.getRegister(reg));
                    } else if (arg1.startsWith("(%")) {
                        String reg = arg1.substring(1);
                        src = new Operand(OpType.MM_REG, Registers.getRegister(reg).getValue());
                    }

                    // arg2
                    if (arg2.startsWith("($0x")) {
                        dest = new Operand(OpType.MM_IMM, Integer.parseInt(arg2.substring(4, arg2.length() - 1)));
                    } else if (arg2.startsWith("%")) {
                        String reg = arg2.substring(1);
                        dest = new Operand(OpType.REG, Registers.getRegister(reg));
                    } else if (arg2.startsWith("(%")) {
                        String reg = arg2.substring(1);
                        dest = new Operand(OpType.MM_REG, Registers.getRegister(reg).getValue());
                    }

                    String name = "MOV_" + src.opType.toString().split("_")[0] + "_" + dest.opType.toString().split("_")[0];
                    op = Opcode.getOpcode(name);
                    break;
                }
                case "push": {
                    if (arg1.startsWith("%")) {
                        src = new Operand(OpType.REG, Registers.getRegister(arg1.substring(1)));
                        op = Opcode.getOpcode("PUSH");
                    }
                    break;
                }
                case "pop": {
                    if (arg1.startsWith("%")) {
                        src = new Operand(OpType.REG, Registers.getRegister(arg1.substring(1)));
                        op = Opcode.getOpcode("POP");
                    }
                    break;
                }
            }
        }
    }

    public Instruct(Opcode op, Operand src, Operand dest) {
        this.op = op;
        this.src = src;
        this.dest = dest;
    }

    public Instruct(Opcode op, Operand src, Operand dest, String sourceCode) {
        this.op = op;
        this.src = src;
        this.dest = dest;
        this.sourceCode = sourceCode;
    }

    public Opcode getOp() {
        return op;
    }

    public Operand getSrc() {
        return src;
    }

    public Operand getDest() {
        return dest;
    }

    public String getSourceCode() {
        return sourceCode;
    }
}
